home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1992, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
-
- /*$Id: gxcmap.c,v 1.3 2000/09/19 19:00:35 lpd Exp $ */
- /* Color mapping for Ghostscript */
- #include "gx.h"
- #include "gserrors.h"
- #include "gsccolor.h"
- #include "gxalpha.h"
- #include "gxcspace.h"
- #include "gxfarith.h"
- #include "gxfrac.h"
- #include "gxdcconv.h"
- #include "gxdevice.h"
- #include "gxcmap.h"
- #include "gxlum.h"
- #include "gzstate.h"
- #include "gxdither.h"
-
- /* Structure descriptor */
- public_st_device_color();
- private
- ENUM_PTRS_WITH(device_color_enum_ptrs, gx_device_color *cptr)
- {
- return ENUM_USING(*cptr->type->stype, vptr, size, index);
- }
- ENUM_PTRS_END
- private RELOC_PTRS_WITH(device_color_reloc_ptrs, gx_device_color *cptr)
- {
- RELOC_USING(*cptr->type->stype, vptr, size);
- }
- RELOC_PTRS_END
-
- /* ------ Trace device mapping procedures ------ */
-
- /* If DEBUG is defined, these procedures substitute for direct calls */
- /* on the device map_{rgb,cmyk}_color procedures. */
-
- gx_color_index
- gx_proc_map_rgb_color(gx_device * dev,
- gx_color_value vr, gx_color_value vg, gx_color_value vb)
- {
- gx_color_index cindex =
- (*dev_proc(dev, map_rgb_color)) (dev, vr, vg, vb);
-
- if_debug5('C', "%s [C]RGB %u,%u,%u -> color 0x%lx\n",
- dev->dname, (uint) vr, (uint) vg, (uint) vb, (ulong) cindex);
- return cindex;
- }
-
- gx_color_index
- gx_proc_map_rgb_alpha_color(gx_device * dev,
- gx_color_value vr, gx_color_value vg, gx_color_value vb, gx_color_value va)
- {
- gx_color_index cindex =
- (*dev_proc(dev, map_rgb_alpha_color)) (dev, vr, vg, vb, va);
-
- if_debug6('C', "[C]%s RGBA %u,%u,%u,%u -> color 0x%lx\n",
- dev->dname, (uint) vr, (uint) vg, (uint) vb, (uint) va,
- (ulong) cindex);
- return cindex;
- }
-
- gx_color_index
- gx_proc_map_cmyk_color(gx_device * dev,
- gx_color_value vc, gx_color_value vm, gx_color_value vy, gx_color_value vk)
- {
- gx_color_index cindex =
- (*dev_proc(dev, map_cmyk_color)) (dev, vc, vm, vy, vk);
-
- if_debug6('C', "[C]%s CMYK %u,%u,%u,%u -> color 0x%lx\n",
- dev->dname, (uint) vc, (uint) vm, (uint) vy, (uint) vk,
- (ulong) cindex);
- return cindex;
- }
-
- /* ---------------- Device color rendering ---------------- */
-
- private cmap_proc_gray(cmap_gray_halftoned);
- private cmap_proc_gray(cmap_gray_direct);
- private cmap_proc_gray(cmap_gray_to_rgb_halftoned);
- private cmap_proc_gray(cmap_gray_to_rgb_direct);
- private cmap_proc_gray(cmap_gray_to_cmyk_halftoned);
- private cmap_proc_gray(cmap_gray_to_cmyk_direct);
- private cmap_proc_rgb(cmap_rgb_halftoned);
- private cmap_proc_rgb(cmap_rgb_direct);
- private cmap_proc_rgb(cmap_rgb_to_gray_halftoned);
- private cmap_proc_rgb(cmap_rgb_to_gray_direct);
- private cmap_proc_rgb(cmap_rgb_to_cmyk);
-
- #define cmap_cmyk_halftoned cmap_cmyk_direct
- private cmap_proc_cmyk(cmap_cmyk_direct);
- private cmap_proc_cmyk(cmap_cmyk_to_gray);
- private cmap_proc_cmyk(cmap_cmyk_to_rgb);
- private cmap_proc_rgb_alpha(cmap_rgb_alpha_halftoned);
- private cmap_proc_rgb_alpha(cmap_rgb_alpha_direct);
-
- /* Procedure names are only guaranteed unique to 23 characters.... */
- private cmap_proc_rgb_alpha(cmap_rgb_alpha2gray_halftoned);
- private cmap_proc_rgb_alpha(cmap_rgb_alpha2gray_direct);
- private cmap_proc_rgb_alpha(cmap_rgb_alpha_to_cmyk);
-
- private const gx_color_map_procs
- cmap_gray_few =
- {cmap_gray_halftoned, cmap_rgb_to_gray_halftoned, cmap_cmyk_to_gray,
- cmap_rgb_alpha2gray_halftoned
- }, cmap_gray_many =
- {cmap_gray_direct, cmap_rgb_to_gray_direct, cmap_cmyk_to_gray,
- cmap_rgb_alpha2gray_direct
- }, cmap_rgb_few =
- {cmap_gray_to_rgb_halftoned, cmap_rgb_halftoned, cmap_cmyk_to_rgb,
- cmap_rgb_alpha_halftoned
- }, cmap_rgb_many =
- {cmap_gray_to_rgb_direct, cmap_rgb_direct, cmap_cmyk_to_rgb,
- cmap_rgb_alpha_direct
- }, cmap_cmyk_few =
- {cmap_gray_to_cmyk_halftoned, cmap_rgb_to_cmyk, cmap_cmyk_halftoned,
- cmap_rgb_alpha_to_cmyk
- }, cmap_cmyk_many =
- {cmap_gray_to_cmyk_direct, cmap_rgb_to_cmyk, cmap_cmyk_direct,
- cmap_rgb_alpha_to_cmyk
- };
-
- const gx_color_map_procs *const cmap_procs_default = &cmap_gray_many;
-
- private const gx_color_map_procs *const cmap_few[] =
- {
- 0, &cmap_gray_few, 0, &cmap_rgb_few, &cmap_cmyk_few
- };
-
- private const gx_color_map_procs *const cmap_many[] =
- {
- 0, &cmap_gray_many, 0, &cmap_rgb_many, &cmap_cmyk_many
- };
-
- /* Determine the color mapping procedures for a device. */
- /* Note that the default procedure doesn't consult the imager state. */
- const gx_color_map_procs *
- gx_get_cmap_procs(const gs_imager_state *pis, const gx_device * dev)
- {
- return (pis->get_cmap_procs)(pis, dev);
- }
- const gx_color_map_procs *
- gx_default_get_cmap_procs(const gs_imager_state *pis, const gx_device * dev)
- {
- return (gx_device_must_halftone(dev) ? cmap_few : cmap_many)
- [dev->color_info.num_components];
- }
-
- /* Set the color mapping procedures in the graphics state. */
- void
- gx_set_cmap_procs(gs_imager_state * pis, const gx_device * dev)
- {
- pis->cmap_procs = gx_get_cmap_procs(pis, dev);
- }
-
- /* Remap the color in the graphics state. */
- int
- gx_remap_color(gs_state * pgs)
- {
- const gs_color_space *pcs = pgs->color_space;
-
- /* The current color in the graphics state is always used for */
- /* the texture, never for the source. */
- return (*pcs->type->remap_color) (pgs->ccolor, pcs, pgs->dev_color,
- (gs_imager_state *) pgs, pgs->device,
- gs_color_select_texture);
- }
-
- /* Indicate that a color space has no underlying concrete space. */
- const gs_color_space *
- gx_no_concrete_space(const gs_color_space * pcs, const gs_imager_state * pis)
- {
- return NULL;
- }
-
- /* Indicate that a color space is concrete. */
- const gs_color_space *
- gx_same_concrete_space(const gs_color_space * pcs, const gs_imager_state * pis)
- {
- return pcs;
- }
-
- /* Indicate that a color cannot be concretized. */
- int
- gx_no_concretize_color(const gs_client_color * pcc, const gs_color_space * pcs,
- frac * pconc, const gs_imager_state * pis)
- {
- return_error(gs_error_rangecheck);
- }
-
- /* By default, remap a color by concretizing it and then */
- /* remapping the concrete color. */
- int
- gx_default_remap_color(const gs_client_color * pcc, const gs_color_space * pcs,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS];
- const gs_color_space *pconcs;
- int code = (*pcs->type->concretize_color)(pcc, pcs, conc, pis);
-
- if (code < 0)
- return code;
- pconcs = cs_concrete_space(pcs, pis);
- return (*pconcs->type->remap_concrete_color)(conc, pdc, pis, dev, select);
- }
-
- /* Color remappers for the standard color spaces. */
- /* Note that we use D... instead of Device... in some places because */
- /* gcc under VMS only retains 23 characters of procedure names. */
-
- #define unit_frac(v, ftemp)\
- (ftemp = (v),\
- (is_fneg(ftemp) ? frac_0 : is_fge1(ftemp) ? frac_1 : float2frac(ftemp)))
-
- /* DeviceGray */
- int
- gx_concretize_DeviceGray(const gs_client_color * pc, const gs_color_space * pcs,
- frac * pconc, const gs_imager_state * pis)
- {
- float ftemp;
-
- pconc[0] = unit_frac(pc->paint.values[0], ftemp);
- return 0;
- }
- int
- gx_remap_concrete_DGray(const frac * pconc,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- if (pis->alpha == gx_max_color_value)
- (*pis->cmap_procs->map_gray)
- (pconc[0], pdc, pis, dev, select);
- else
- (*pis->cmap_procs->map_rgb_alpha)
- (pconc[0], pconc[0], pconc[0], cv2frac(pis->alpha),
- pdc, pis, dev, select);
- return 0;
- }
- int
- gx_remap_DeviceGray(const gs_client_color * pc, const gs_color_space * pcs,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- float ftemp;
- frac fgray = unit_frac(pc->paint.values[0], ftemp);
-
- if (pis->alpha == gx_max_color_value)
- (*pis->cmap_procs->map_gray)
- (fgray, pdc, pis, dev, select);
- else
- (*pis->cmap_procs->map_rgb_alpha)
- (fgray, fgray, fgray, cv2frac(pis->alpha), pdc, pis, dev, select);
- return 0;
- }
-
- /* DeviceRGB */
- int
- gx_concretize_DeviceRGB(const gs_client_color * pc, const gs_color_space * pcs,
- frac * pconc, const gs_imager_state * pis)
- {
- float ftemp;
-
- pconc[0] = unit_frac(pc->paint.values[0], ftemp);
- pconc[1] = unit_frac(pc->paint.values[1], ftemp);
- pconc[2] = unit_frac(pc->paint.values[2], ftemp);
- return 0;
- }
- int
- gx_remap_concrete_DRGB(const frac * pconc,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- if (pis->alpha == gx_max_color_value)
- gx_remap_concrete_rgb(pconc[0], pconc[1], pconc[2],
- pdc, pis, dev, select);
- else
- gx_remap_concrete_rgb_alpha(pconc[0], pconc[1], pconc[2],
- cv2frac(pis->alpha),
- pdc, pis, dev, select);
- return 0;
- }
- int
- gx_remap_DeviceRGB(const gs_client_color * pc, const gs_color_space * pcs,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- float ftemp;
- frac fred = unit_frac(pc->paint.values[0], ftemp), fgreen = unit_frac(pc->paint.values[1], ftemp),
- fblue = unit_frac(pc->paint.values[2], ftemp);
-
- if (pis->alpha == gx_max_color_value)
- gx_remap_concrete_rgb(fred, fgreen, fblue,
- pdc, pis, dev, select);
- else
- gx_remap_concrete_rgb_alpha(fred, fgreen, fblue, cv2frac(pis->alpha),
- pdc, pis, dev, select);
- return 0;
- }
-
- /* DeviceCMYK */
- int
- gx_concretize_DeviceCMYK(const gs_client_color * pc, const gs_color_space * pcs,
- frac * pconc, const gs_imager_state * pis)
- {
- float ftemp;
-
- pconc[0] = unit_frac(pc->paint.values[0], ftemp);
- pconc[1] = unit_frac(pc->paint.values[1], ftemp);
- pconc[2] = unit_frac(pc->paint.values[2], ftemp);
- pconc[3] = unit_frac(pc->paint.values[3], ftemp);
- return 0;
- }
- int
- gx_remap_concrete_DCMYK(const frac * pconc,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- /****** IGNORE alpha ******/
- gx_remap_concrete_cmyk(pconc[0], pconc[1], pconc[2], pconc[3], pdc,
- pis, dev, select);
- return 0;
- }
- int
- gx_remap_DeviceCMYK(const gs_client_color * pc, const gs_color_space * pcs,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- /****** IGNORE alpha ******/
- float ft0, ft1, ft2, ft3;
-
- gx_remap_concrete_cmyk(unit_frac(pc->paint.values[0], ft0),
- unit_frac(pc->paint.values[1], ft1),
- unit_frac(pc->paint.values[2], ft2),
- unit_frac(pc->paint.values[3], ft3),
- pdc, pis, dev, select);
- return 0;
- }
-
- /* ------ Render Gray color. ------ */
-
- private void
- cmap_gray_halftoned(frac gray, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- if (gx_render_gray(gx_map_color_frac(pis, gray, effective_transfer.colored.gray), pdc, pis, dev, select) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
-
- private void
- cmap_gray_direct(frac gray, gx_device_color * pdc, const gs_imager_state * pis,
- gx_device * dev, gs_color_select_t select)
- {
- frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
- gx_color_value cv_gray = frac2cv(mgray);
- gx_color_index color =
- (pis->alpha == gx_max_color_value ?
- gx_map_rgb_color(dev, cv_gray, cv_gray, cv_gray) :
- gx_map_rgb_alpha_color(dev, cv_gray, cv_gray, cv_gray, pis->alpha));
-
- if (color == gx_no_color_index) {
- if (gx_render_gray(mgray, pdc, pis, dev, select) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- return;
- }
- color_set_pure(pdc, color);
- }
-
- private void
- cmap_gray_to_rgb_halftoned(frac gray, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- cmap_rgb_halftoned(gray, gray, gray, pdc, pis, dev, select);
- }
-
- private void
- cmap_gray_to_rgb_direct(frac gray, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- cmap_rgb_direct(gray, gray, gray, pdc, pis, dev, select);
- }
-
- private void
- cmap_gray_to_cmyk_halftoned(frac gray, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- { /*
- * Per the last paragraph of section 6.3 (p. 309) of the
- * PostScript Language Reference Manual, 2nd Edition,
- * we must bypass the C, M, and Y transfer functions in this case.
- */
- frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
-
- if (gx_render_gray(mgray, pdc, pis, dev, select) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
-
- private void
- cmap_gray_to_cmyk_direct(frac gray, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- { /*
- * Per the last paragraph of section 6.3 (p. 309) of the
- * PostScript Language Reference Manual, 2nd Edition,
- * we must bypass the C, M, and Y transfer functions in this case.
- */
- frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
- frac mblack = frac_1 - mgray;
- gx_color_index color =
- gx_map_cmyk_color(dev,
- frac2cv(frac_0), frac2cv(frac_0),
- frac2cv(frac_0), frac2cv(mblack));
-
- if (color != gx_no_color_index) {
- color_set_pure(pdc, color);
- return;
- }
- if (gx_render_gray(mgray, pdc, pis, dev, select) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
-
- /* ------ Render RGB color. ------ */
-
- /*
- * This code should test r == g and g == b and then use the gray
- * rendering procedures. The Adobe documentation allows this:
- * conversion between color spaces occurs before the transfer function
- * and halftoning. However, output from FrameMaker (mis)uses the
- * transfer function to provide the equivalent of indexed color;
- * it requires the color components to be passed through unchanged.
- * For this reason, we have to make the check after the transfer
- * function rather than before.
- *
- * Since this procedure is used so heavily, we duplicate most of its code
- * rather than making a text for color_info.max_color >= 31.
- */
-
- private void
- cmap_rgb_halftoned(frac r, frac g, frac b, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
- frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
- frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
-
- if ((mred == mgreen && mred == mblue ? /* gray shade */
- gx_render_gray(mred, pdc, pis, dev, select) :
- gx_render_rgb(mred, mgreen, mblue, pdc, pis, dev, select)) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
-
- private void
- cmap_rgb_direct(frac r, frac g, frac b, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
- frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
- frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
- gx_color_index color =
- (pis->alpha == gx_max_color_value ?
- gx_map_rgb_color(dev, frac2cv(mred), frac2cv(mgreen),
- frac2cv(mblue)) :
- gx_map_rgb_alpha_color(dev, frac2cv(mred), frac2cv(mgreen),
- frac2cv(mblue), pis->alpha));
-
- if (color != gx_no_color_index) {
- color_set_pure(pdc, color);
- return;
- }
- if ((mred == mgreen && mred == mblue ? /* gray shade */
- gx_render_gray(mred, pdc, pis, dev, select) :
- gx_render_rgb(mred, mgreen, mblue, pdc, pis, dev, select)) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
-
- private void
- cmap_rgb_to_gray_halftoned(frac r, frac g, frac b, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- cmap_gray_halftoned(color_rgb_to_gray(r, g, b, pis), pdc, pis, dev, select);
- }
-
- private void
- cmap_rgb_to_gray_direct(frac r, frac g, frac b, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- cmap_gray_direct(color_rgb_to_gray(r, g, b, pis), pdc, pis, dev, select);
- }
-
- private void
- cmap_rgb_to_cmyk(frac r, frac g, frac b, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- frac cmyk[4];
-
- color_rgb_to_cmyk(r, g, b, pis, cmyk);
- (*pis->cmap_procs->map_cmyk) (cmyk[0], cmyk[1], cmyk[2], cmyk[3], pdc, pis, dev, select);
- }
-
- /* ------ Render CMYK color. ------ */
-
- private void
- cmap_cmyk_to_gray(frac c, frac m, frac y, frac k, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- (*pis->cmap_procs->map_gray) (color_cmyk_to_gray(c, m, y, k, pis), pdc, pis, dev, select);
- }
-
- private void
- cmap_cmyk_direct(frac c, frac m, frac y, frac k, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- frac mcyan = frac_1 - gx_map_color_frac(pis, frac_1 - c, effective_transfer.colored.red);
- frac mmagenta = frac_1 - gx_map_color_frac(pis, frac_1 - m, effective_transfer.colored.green);
- frac myellow = frac_1 - gx_map_color_frac(pis, frac_1 - y, effective_transfer.colored.blue);
- frac mblack = frac_1 - gx_map_color_frac(pis, frac_1 - k, effective_transfer.colored.gray);
-
- /* We make a test for direct vs. halftoned, rather than */
- /* duplicating most of the code of this procedure. */
- if (!gx_color_device_must_halftone(dev)) {
- gx_color_index color =
- gx_map_cmyk_color(dev,
- frac2cv(mcyan), frac2cv(mmagenta),
- frac2cv(myellow), frac2cv(mblack));
-
- if (color != gx_no_color_index) {
- color_set_pure(pdc, color);
- return;
- }
- }
- /* Don't convert colors with C = M = Y to gray shades: */
- /* on a CMYK device, this may produce quite different output. */
- if (gx_render_cmyk(mcyan, mmagenta, myellow, mblack, pdc, pis, dev, select) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
-
- private void
- cmap_cmyk_to_rgb(frac c, frac m, frac y, frac k, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- frac rgb[3];
-
- color_cmyk_to_rgb(c, m, y, k, pis, rgb);
- (*pis->cmap_procs->map_rgb) (rgb[0], rgb[1], rgb[2], pdc, pis, dev, select);
- }
-
- /* ------ Render RGB+alpha color. ------ */
-
- #ifdef PREMULTIPLY_TOWARDS_WHITE
- # define alpha_bias_value frac_1 - alpha
- # define alpha_bias(v) ((v) + alpha_bias_value
- #else
- # define alpha_bias(v) (v)
- #endif
-
- private void
- cmap_rgb_alpha2gray_halftoned(frac r, frac g, frac b, frac alpha,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- frac gray = color_rgb_to_gray(r, g, b, pis);
-
- if (alpha != frac_1) /* premultiply */
- gray = alpha_bias((frac) ((long)gray * alpha / frac_1));
- if (gx_render_gray_alpha(gx_map_color_frac(pis, gray, effective_transfer.colored.gray), frac2cv(alpha), pdc, pis, dev, select) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
-
- private void
- cmap_rgb_alpha2gray_direct(frac r, frac g, frac b, frac alpha,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- frac gray = color_rgb_to_gray(r, g, b, pis);
-
- if (alpha != frac_1) /* premultiply */
- gray = alpha_bias((frac) ((long)gray * alpha / frac_1));
- {
- frac mgray =
- gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
- gx_color_value cv_gray = frac2cv(mgray);
- gx_color_index color =
- (alpha == frac_1 ?
- gx_map_rgb_color(dev, cv_gray, cv_gray, cv_gray) :
- gx_map_rgb_alpha_color(dev, cv_gray, cv_gray, cv_gray, frac2cv(alpha)));
-
- if (color == gx_no_color_index) {
- if (gx_render_gray_alpha(mgray, frac2cv(alpha), pdc, pis, dev, select) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- return;
- }
- color_set_pure(pdc, color);
- }
- }
-
- private void
- cmap_rgb_alpha_halftoned(frac r, frac g, frac b, frac alpha,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- frac red = r, green = g, blue = b;
-
- if (alpha != frac_1) { /* premultiply */
- red = alpha_bias((frac) ((long)red * alpha / frac_1));
- green = alpha_bias((frac) ((long)green * alpha / frac_1));
- blue = alpha_bias((frac) ((long)blue * alpha / frac_1));
- } {
- frac mred =
- gx_map_color_frac(pis, red, effective_transfer.colored.red);
- frac mgreen =
- gx_map_color_frac(pis, green, effective_transfer.colored.green);
- frac mblue =
- gx_map_color_frac(pis, blue, effective_transfer.colored.blue);
- gx_color_value cv_alpha = frac2cv(alpha);
-
- if ((mred == mgreen && mred == mblue ? /* gray shade */
- gx_render_gray_alpha(mred, cv_alpha, pdc, pis, dev, select) :
- gx_render_rgb_alpha(mred, mgreen, mblue, cv_alpha, pdc, pis, dev, select)) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
- }
-
- private void
- cmap_rgb_alpha_direct(frac r, frac g, frac b, frac alpha, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
- {
- frac red = r, green = g, blue = b;
-
- if (alpha != frac_1) { /* premultiply */
- red = alpha_bias((frac) ((long)red * alpha / frac_1));
- green = alpha_bias((frac) ((long)green * alpha / frac_1));
- blue = alpha_bias((frac) ((long)blue * alpha / frac_1));
- } {
- frac mred =
- gx_map_color_frac(pis, red, effective_transfer.colored.red);
- frac mgreen =
- gx_map_color_frac(pis, green, effective_transfer.colored.green);
- frac mblue =
- gx_map_color_frac(pis, blue, effective_transfer.colored.blue);
- gx_color_value cv_alpha = frac2cv(alpha);
- gx_color_index color =
- (cv_alpha == gx_max_color_value ?
- gx_map_rgb_color(dev, frac2cv(mred), frac2cv(mgreen),
- frac2cv(mblue)) :
- gx_map_rgb_alpha_color(dev, frac2cv(mred), frac2cv(mgreen),
- frac2cv(mblue), cv_alpha));
-
- if (color != gx_no_color_index) {
- color_set_pure(pdc, color);
- return;
- }
- if ((mred == mgreen && mred == mblue ? /* gray shade */
- gx_render_gray_alpha(mred, cv_alpha, pdc, pis, dev, select) :
- gx_render_rgb_alpha(mred, mgreen, mblue, cv_alpha, pdc, pis, dev, select)) == 1)
- gx_color_load_select(pdc, pis, dev, select);
- }
- }
-
- /* Currently CMYK devices can't handle alpha. */
- /* Just multiply the values towards white. */
- private void
- cmap_rgb_alpha_to_cmyk(frac r, frac g, frac b, frac alpha,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select)
- {
- #ifdef PREMULTIPLY_TOWARDS_WHITE
- # undef alpha_bias_value
- frac alpha_bias_value = frac_1 - alpha;
-
- #endif
-
- cmap_rgb_to_cmyk(alpha_bias((frac) ((long)r * alpha / frac_1)),
- alpha_bias((frac) ((long)g * alpha / frac_1)),
- alpha_bias((frac) ((long)b * alpha / frac_1)),
- pdc, pis, dev, select);
- }
-
- #undef alpha_bias
- #undef alpha_bias_value
-
- /* ------ Transfer function mapping ------ */
-
- /* Define an identity transfer function. */
- float
- gs_identity_transfer(floatp value, const gx_transfer_map * pmap)
- {
- return value;
- }
-
- /* Define the generic transfer function for the library layer. */
- /* This just returns what's already in the map. */
- float
- gs_mapped_transfer(floatp value, const gx_transfer_map * pmap)
- {
- return gx_map_color_float(pmap, value);
- }
-
- /* Set a transfer map to the identity map. */
- void
- gx_set_identity_transfer(gx_transfer_map *pmap)
- {
- int i;
-
- pmap->proc = gs_identity_transfer;
- /* We still have to fill in the cached values. */
- for (i = 0; i < transfer_map_size; ++i)
- pmap->values[i] = bits2frac(i, log2_transfer_map_size);
- }
-
- #if FRAC_MAP_INTERPOLATE /* NOTA BENE */
-
- /* Map a color fraction through a transfer map. */
- /* We only use this if we are interpolating. */
- frac
- gx_color_frac_map(frac cv, const frac * values)
- {
- #define cp_frac_bits (frac_bits - log2_transfer_map_size)
- int cmi = frac2bits_floor(cv, log2_transfer_map_size);
- frac mv = values[cmi];
- int rem, mdv;
-
- /* Interpolate between two adjacent values if needed. */
- rem = cv - bits2frac(cmi, log2_transfer_map_size);
- if (rem == 0)
- return mv;
- mdv = values[cmi + 1] - mv;
- #if arch_ints_are_short
- /* Only use long multiplication if necessary. */
- if (mdv < -1 << (16 - cp_frac_bits) ||
- mdv > 1 << (16 - cp_frac_bits)
- )
- return mv + (uint) (((ulong) rem * mdv) >> cp_frac_bits);
- #endif
- return mv + ((rem * mdv) >> cp_frac_bits);
- #undef cp_frac_bits
- }
-
- #endif /* FRAC_MAP_INTERPOLATE */
-
- /* ------ Default device color mapping ------ */
-
- /* RGB mapping for black-and-white devices */
-
- /* White-on-black */
- gx_color_index
- gx_default_w_b_map_rgb_color(gx_device * dev,
- gx_color_value r, gx_color_value g, gx_color_value b)
- { /* Map values >= 1/2 to 1, < 1/2 to 0. */
- return ((r | g | b) > gx_max_color_value / 2 ?
- (gx_color_index) 1 : (gx_color_index) 0);
- }
- int
- gx_default_w_b_map_color_rgb(gx_device * dev, gx_color_index color,
- gx_color_value prgb[3])
- { /* Map 1 to max_value, 0 to 0. */
- prgb[0] = prgb[1] = prgb[2] = -(gx_color_value) color;
- return 0;
- }
- /* Black-on-white */
- gx_color_index
- gx_default_b_w_map_rgb_color(gx_device * dev,
- gx_color_value r, gx_color_value g, gx_color_value b)
- { /* Map values >= 1/2 to 0, < 1/2 to 1. */
- return ((r | g | b) > gx_max_color_value / 2 ?
- (gx_color_index) 0 : (gx_color_index) 1);
- }
- int
- gx_default_b_w_map_color_rgb(gx_device * dev, gx_color_index color,
- gx_color_value prgb[3])
- { /* Map 0 to max_value, 1 to 0. */
- prgb[0] = prgb[1] = prgb[2] = -((gx_color_value) color ^ 1);
- return 0;
- }
-
- /* RGB mapping for gray-scale devices */
-
- gx_color_index
- gx_default_gray_map_rgb_color(gx_device * dev,
- gx_color_value r, gx_color_value g, gx_color_value b)
- { /* We round the value rather than truncating it. */
- gx_color_value gray =
- (((r * (ulong) lum_red_weight) +
- (g * (ulong) lum_green_weight) +
- (b * (ulong) lum_blue_weight) +
- (lum_all_weights / 2)) / lum_all_weights
- * dev->color_info.max_gray +
- (gx_max_color_value / 2)) / gx_max_color_value;
-
- return gray;
- }
-
- int
- gx_default_gray_map_color_rgb(gx_device * dev, gx_color_index color,
- gx_color_value prgb[3])
- {
- gx_color_value gray =
- color * gx_max_color_value / dev->color_info.max_gray;
-
- prgb[0] = gray;
- prgb[1] = gray;
- prgb[2] = gray;
- return 0;
- }
-
- /* RGB mapping for 24-bit true (RGB) color devices */
-
- gx_color_index
- gx_default_rgb_map_rgb_color(gx_device * dev,
- gx_color_value r, gx_color_value g, gx_color_value b)
- {
- if (dev->color_info.depth == 24)
- return gx_color_value_to_byte(b) +
- ((uint) gx_color_value_to_byte(g) << 8) +
- ((ulong) gx_color_value_to_byte(r) << 16);
- else {
- int bpc = dev->color_info.depth / 3;
- int drop = sizeof(gx_color_value) * 8 - bpc;
-
- return ((((r >> drop) << bpc) + (g >> drop)) << bpc) + (b >> drop);
- }
- }
-
- /* Map a color index to a r-g-b color. */
- int
- gx_default_rgb_map_color_rgb(gx_device * dev, gx_color_index color,
- gx_color_value prgb[3])
- {
- if (dev->color_info.depth == 24) {
- prgb[0] = gx_color_value_from_byte(color >> 16);
- prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
- prgb[2] = gx_color_value_from_byte(color & 0xff);
- } else {
- uint bits_per_color = dev->color_info.depth / 3;
- uint color_mask = (1 << bits_per_color) - 1;
-
- prgb[0] = ((color >> (bits_per_color * 2)) & color_mask) *
- (ulong) gx_max_color_value / color_mask;
- prgb[1] = ((color >> (bits_per_color)) & color_mask) *
- (ulong) gx_max_color_value / color_mask;
- prgb[2] = (color & color_mask) *
- (ulong) gx_max_color_value / color_mask;
- }
- return 0;
- }
-
- /* CMYK mapping for RGB devices (should never be called!) */
-
- gx_color_index
- gx_default_map_cmyk_color(gx_device * dev,
- gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k)
- { /* Convert to RGB */
- frac rgb[3];
-
- color_cmyk_to_rgb(cv2frac(c), cv2frac(m), cv2frac(y), cv2frac(k),
- NULL, rgb);
- return gx_map_rgb_color(dev, frac2cv(rgb[0]),
- frac2cv(rgb[1]), frac2cv(rgb[2]));
- }
-
- /* Mapping for CMYK devices */
-
- gx_color_index
- cmyk_1bit_map_cmyk_color(gx_device * dev,
- gx_color_value c, gx_color_value m,
- gx_color_value y, gx_color_value k)
- {
- #define CV_BIT(v) ((v) >> (gx_color_value_bits - 1))
- return (gx_color_index)
- (CV_BIT(k) + (CV_BIT(y) << 1) + (CV_BIT(m) << 2) + (CV_BIT(c) << 3));
- #undef CV_BIT
- }
-
- int
- cmyk_1bit_map_color_rgb(gx_device * dev, gx_color_index color,
- gx_color_value prgb[3])
- {
- if (color & 1)
- prgb[0] = prgb[1] = prgb[2] = 0;
- else {
- prgb[0] = (color & 8 ? 0 : gx_max_color_value);
- prgb[1] = (color & 4 ? 0 : gx_max_color_value);
- prgb[2] = (color & 2 ? 0 : gx_max_color_value);
- }
- return 0;
- }
-
- gx_color_index
- cmyk_8bit_map_cmyk_color(gx_device * dev,
- gx_color_value c, gx_color_value m,
- gx_color_value y, gx_color_value k)
- {
- gx_color_index color =
- gx_color_value_to_byte(k) +
- ((uint)gx_color_value_to_byte(y) << 8) +
- ((uint)gx_color_value_to_byte(m) << 16) +
- ((uint)gx_color_value_to_byte(c) << 24);
-
- return (color == gx_no_color_index ? color ^ 1 : color);
- }
-
- int
- cmyk_8bit_map_color_rgb(gx_device * dev, gx_color_index color,
- gx_color_value prgb[3])
- {
- int
- not_k = ~color & 0xff,
- r = not_k - (color >> 24),
- g = not_k - ((color >> 16) & 0xff),
- b = not_k - ((color >> 8) & 0xff);
-
- prgb[0] = (r < 0 ? 0 : gx_color_value_from_byte(r));
- prgb[1] = (g < 0 ? 0 : gx_color_value_from_byte(g));
- prgb[2] = (b < 0 ? 0 : gx_color_value_from_byte(b));
- return 0;
- }
-
- /* Default mapping between RGB+alpha and RGB. */
-
- gx_color_index
- gx_default_map_rgb_alpha_color(gx_device * dev,
- gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha)
- { /* Colors have been premultiplied: we don't need to do it here. */
- return gx_map_rgb_color(dev, r, g, b);
- }
-
- int
- gx_default_map_color_rgb_alpha(gx_device * dev, gx_color_index color,
- gx_color_value prgba[4])
- {
- prgba[3] = gx_max_color_value; /* alpha = 1 */
- return (*dev_proc(dev, map_color_rgb)) (dev, color, prgba);
- }
-